import { IPromiseDefer, createDefer } from "./utils/create-defer";

export interface ITimer {
    defer: IPromiseDefer<any>;
    time: number;
    uid: number;
    started: boolean;
}

export class Timer {

    protected uid = 0;

    protected readonly timer = new Map<number, ITimer>();

    protected _sleep!: ((time: number) => Promise<void>) | null;

    protected runJob = () => {
        if (this.timer.size) {
            // 触发立即执行
            Array.from(this.timer).forEach(([uid, iTask]) => {
                if (this._sleep && !iTask.started) {
                    iTask.defer.resolve(this._sleep(iTask.time));
                    iTask.started = true;
                }
            })
        }
    }

    public setSleepFn = (sleep: null | ((time: number) => Promise<void>)) => {
        this._sleep = sleep;
        this.runJob();
    }

    public wrapFn(uid: number, fn: Function, ...args: any): () => any {
        let timer = this.timer;
        return function () {
            if (timer.has(uid)) {
                try {
                    const currentTask = timer.get(uid)!;
                    currentTask.started = true;
                    fn(...args);
                } finally {
                    timer.delete(uid);
                    timer = null!;
                }
            }
        };
    }

    public setTimeout = (fn: Function, time: number = 0, ...args: any[]) => {
        const val = ++this.uid;
        const defer = createDefer();
        defer.promise.then(this.wrapFn(val, fn, ...args));
        this.timer.set(val, {
            defer,
            uid: val,
            time,
            started: false,
        });
        this.runJob();
        return val;
    }

    public clearTimeout = (uid: any) => {
        if (typeof uid === 'number' && this.timer.has(uid)) {
            this.timer.delete(uid);
        }
    }

    public setInterval = () => {

    }

    public clearInterval = () => {

    }
}

export const globalTimer = new Timer();
